#include "udpServer.hpp"
#include "onlineManager.hpp"
#include <memory>
#include <fstream>
#include <unordered_map>
#include <signal.h> // 如果我不想重启服务器，对字典进行更新

using namespace std;
using namespace Serevr;

const std::string dictTxt = "./dict.txt";

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << "  local port\n\n";
}

unordered_map<string, string> dict;

static bool cutString(const string &target, string *s1, string *s2, const string &sep)
{
    // hello:你好
    auto pos = target.find(sep);
    if (pos == string::npos)
        return false;
    *s1 = target.substr(0, pos);           // [)
    *s2 = target.substr(pos + sep.size()); // [)
    return true;
}

static void debugPrint()
{
    for (const auto &dt : dict)
    {
        cout << dt.first << " # " << dt.second << endl;
    }
}

static void initDict()
{
    ifstream in(dictTxt, std::ios::binary);
    if (!in.is_open())
    {
        std::cerr << "open file " << dictTxt << "error" << endl;
        exit(OPRN_ERR);
    }
    string line;
    string key, value;

    while (getline(in, line))
    {
        // cout << line << endl;
        if (cutString(line, &key, &value, ":"))
        {
            dict.insert(make_pair(key, value));
        }
    }
    // debugPrint();
    cout << "load dict success" << endl;
    in.close();
}

// demo 1
void handlerMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    // 就可以对message进行特定的业务处理，而不关心message怎么来的 --- sever通信和业务逻辑解耦！
    // 婴儿版业务逻辑
    string response_message;
    auto iter = dict.find(message); // 迭代器指针
    if (iter == dict.end())
        response_message = "unknown";
    else
        response_message = iter->second;

    // 开始返回
    struct sockaddr_in client;
    bzero(&client, sizeof(client));

    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    client.sin_addr.s_addr = inet_addr(clientip.c_str());

    sendto(sockfd, response_message.c_str(), response_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
}

void reinitDict(int signum)
{
    (void)signum;
    initDict();
}

// demo 2
void execCommand(int sockfd, string clientip, uint16_t clientport, string cmd)
{
    // 1.cmd解析，ls -a -l
    // 2.如果必要，可能需要fork,exec*
    string response;
    FILE *fp = popen(cmd.c_str(), "r");
    if (fp == nullptr)
        response = cmd + " exec failed";
    char line[1024];
    while (fgets(line, sizeof(line), fp))
    {
        response += line;
    }
    pclose(fp);

    // 开始返回
    struct sockaddr_in client;
    bzero(&client, sizeof(client));

    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    client.sin_addr.s_addr = inet_addr(clientip.c_str());

    sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));
}

OnlineManager onlineuser;
// demo 3
void routineMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    if (message == "online")
        onlineuser.addUser(clientip, clientport);
    if (message == "offonline")
        onlineuser.delUser(clientip, clientport);
    if (onlineuser.isOnline(clientip, clientport))
    {
        // 消息的路由
        onlineuser.broadcastMessage(sockfd,clientip,clientport, message);
    }
    else
    {
        // 开始返回
        struct sockaddr_in client;
        bzero(&client, sizeof(client));

        client.sin_family = AF_INET;
        client.sin_port = htons(clientport);
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        string response = "你还没有上线,请先上线,运行:online";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));
    }
}

// ./udpServer port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    // signal(2,reinitDict); // 热键，可以不用重启进程，对服务器字典更新
    uint16_t port = atoi(argv[1]);
    // string ip = argv[1];
    // std::unique_ptr<udpServer> usvr (new udpServer(handlerMessage,port));
    // std::unique_ptr<udpServer> usvr (new udpServer(execCommand,port));
    std::unique_ptr<udpServer> usvr(new udpServer(routineMessage, port)); // 聊天室，客户端出入online就上线

    // initDict();
    usvr->initServer();
    usvr->start();
    return 0;
}